﻿
namespace SistemaLogistica.DataAccess
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Common;
    using SistemaLogistica.Business.Entities;

    public class NotaSalidaData : BaseDataAccess
    {
        private NotaSalidaData() { }

        private readonly static NotaSalidaData instancia = new NotaSalidaData();

        public static NotaSalidaData Instancia
        {
            get { return instancia; }
        }

        public List<NotaSalida> Listar()
        {
            List<NotaSalida> notaSalidas = new List<NotaSalida>();

            DbCommand command = db.GetStoredProcCommand("GetAllFromNotaSalida");
            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    NotaSalida notaSalida = new NotaSalida
                    {
                        IdNotaSalida = dr.GetInt32(dr.GetOrdinal("IdNotaSalida")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("Fecha")),
                        Empleados = EmpleadoData.Instancia.ObtenerPorID(dr.GetInt16(dr.GetOrdinal("IDEmpleado"))),
                        OrdenPedido = OrdenPedidoData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IDOrdenPedido"))),
                        Detalle = DetalleNotaSalidaData.Instancia.ListarPorNotaSalida(dr.GetInt32(dr.GetOrdinal("IdNotaSalida")))
                    };
                    notaSalidas.Add(notaSalida);
                }
            }
            return notaSalidas;
        }

        public List<NotaSalida> Buscar(DateTime desde, DateTime hasta)
        {
            List<NotaSalida> notaSalidas = new List<NotaSalida>();

            DbCommand command = db.GetStoredProcCommand("GetNotaSalidaByFecha");
            db.AddInParameter(command, "desde", DbType.Date, desde);
            db.AddInParameter(command, "hasta", DbType.Date, hasta);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    NotaSalida notaSalida = new NotaSalida
                    {
                        IdNotaSalida = dr.GetInt32(dr.GetOrdinal("IdNotaSalida")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("Fecha")),
                        Empleados = EmpleadoData.Instancia.ObtenerPorID(dr.GetInt16(dr.GetOrdinal("IDEmpleado"))),
                        OrdenPedido = OrdenPedidoData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IDOrdenPedido"))),
                        Detalle = DetalleNotaSalidaData.Instancia.ListarPorNotaSalida(dr.GetInt32(dr.GetOrdinal("IdNotaSalida")))
                    };
                    notaSalidas.Add(notaSalida);

                }
            }
            return notaSalidas;
        }

        public NotaSalida ObtenerPorID(int idNotaSalida)
        {
            NotaSalida notaSalida = null;

            DbCommand command = db.GetStoredProcCommand("GetNotaSalidaByIdNotaSalida");
            db.AddInParameter(command, "idNotaSalida", DbType.Int32, idNotaSalida);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                if (dr.Read())
                {
                    notaSalida = new NotaSalida
                    {
                        IdNotaSalida = dr.GetInt32(dr.GetOrdinal("IdNotaSalida")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("Fecha")),
                        Empleados = EmpleadoData.Instancia.ObtenerPorID(dr.GetInt16(dr.GetOrdinal("IDEmpleado"))),
                        OrdenPedido = OrdenPedidoData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IDOrdenPedido"))),
                        Detalle = DetalleNotaSalidaData.Instancia.ListarPorNotaSalida(dr.GetInt32(dr.GetOrdinal("IdNotaSalida")))
                    };
                }
            }
            return notaSalida;
        }

        public int Registrar(NotaSalida notaSalida)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        #region 1.- Registrar Nota Salida

                        DbCommand dbcIngreso = db.GetStoredProcCommand("InsertNotaSalida");

                        db.AddOutParameter(dbcIngreso, "IdNotaSalida", DbType.Int32, 10);
                        db.AddInParameter(dbcIngreso, "fecha", DbType.DateTime, notaSalida.Fecha);
                        db.AddInParameter(dbcIngreso, "IdEmpleado", DbType.Int32, notaSalida.Empleados.IdEmpleado);
                        db.AddInParameter(dbcIngreso, "IdOrdenPedido", DbType.Int32, notaSalida.OrdenPedido.IdOrdenPedido);
                        db.AddInParameter(dbcIngreso, "descripcion", DbType.String, notaSalida.Descripcion);
                        db.ExecuteNonQuery(dbcIngreso, transaction);
                        notaSalida.IdNotaSalida = Convert.ToInt32(db.GetParameterValue(dbcIngreso, "IdNotaSalida"));

                        #endregion
                        #region 2.- Registrar Detalles del Ingreso

                        DbCommand dbcDetalle = db.GetStoredProcCommand("InsertDetalleNotaSalida");

                        db.AddInParameter(dbcDetalle, "cantidad", DbType.Decimal);
                        db.AddInParameter(dbcDetalle, "IdNotaSalida", DbType.Int32);
                        db.AddInParameter(dbcDetalle, "IdBien", DbType.Int32);


                        DbCommand dbcProducto = db.GetStoredProcCommand("InsertDatosSalidaProducto");
                        db.AddInParameter(dbcProducto, "IdBien", DbType.Int32);
                        db.AddInParameter(dbcProducto, "stockActual", DbType.Decimal);

                        foreach (DetalleNotaSalida detalle in notaSalida.Detalle)
                        {
                            #region 2.1.- Verificar la existencia de Productos
                            // Si existe: Actualizar Cantidad
                            // No existe: Registrar Producto

                            db.SetParameterValue(dbcProducto, "IdBien", detalle.Bien.IdBien);
                            db.SetParameterValue(dbcProducto, "stockActual", -detalle.Cantidad);
                            db.ExecuteNonQuery(dbcProducto, transaction);

                            #endregion

                            #region 2.2.- Registrar Detalle

                            db.SetParameterValue(dbcDetalle, "cantidad", detalle.Cantidad);
                            db.SetParameterValue(dbcDetalle, "IdNotaSalida", notaSalida.IdNotaSalida);
                            db.SetParameterValue(dbcDetalle, "IdBien", detalle.Bien.IdBien);
                            db.ExecuteNonQuery(dbcDetalle, transaction);

                            #endregion
                        }

                        #endregion

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }

            return notaSalida.IdNotaSalida;
        }

        public void Modificar(NotaSalida notaSalida)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        #region 1.- Retornar a su estado Inicial

                        #region 1.1.- Recoger Informacion Antigua

                        List<DetalleNotaSalida> detalle = DetalleNotaSalidaData.Instancia.ListarPorNotaSalida(notaSalida.IdNotaSalida);

                        #endregion
                        #region 1.2.- Restar Cantidad de Bien

                        DbCommand dbcBienEdit = db.GetStoredProcCommand("InsertDatosSalidaProducto");
                        db.AddInParameter(dbcBienEdit, "IdBien", DbType.Int32);
                        db.AddInParameter(dbcBienEdit, "stockActual", DbType.Decimal);
                        foreach (DetalleNotaSalida item in detalle)
                        {
                            db.SetParameterValue(dbcBienEdit, "stockActual", item.Cantidad);
                            db.SetParameterValue(dbcBienEdit, "IdBien", item.Bien.IdBien);

                            db.ExecuteNonQuery(dbcBienEdit, transaction);
                        }

                        #endregion
                        #region 1.3.- Eliminar Detalle NotaSalida

                        DbCommand dbcDetalleEdit = db.GetStoredProcCommand("DeleteDetalleNotaSalida");

                        db.AddInParameter(dbcDetalleEdit, "IdNotaSalida", DbType.Int32);
                        db.AddInParameter(dbcDetalleEdit, "IdBien", DbType.Int32);

                        foreach (DetalleNotaSalida item in detalle)
                        {
                            db.SetParameterValue(dbcDetalleEdit, "IdNotaSalida", notaSalida.IdNotaSalida);
                            db.SetParameterValue(dbcDetalleEdit, "IdBien", item.Bien.IdBien);
                            db.ExecuteNonQuery(dbcDetalleEdit, transaction);
                        }

                        #endregion

                        #endregion
                        #region 2.- Ingresar la Nueva Informacion

                        #region 2.1.- Registrar Nota Ingreso

                        DbCommand dbcIngreso = db.GetStoredProcCommand("UpdateNotaSalida");

                        db.AddInParameter(dbcIngreso, "IdNotaSalida", DbType.Int32, notaSalida.IdNotaSalida);
                        db.AddInParameter(dbcIngreso, "fecha", DbType.DateTime, notaSalida.Fecha);
                        db.AddInParameter(dbcIngreso, "IdEmpleado", DbType.Int32, notaSalida.Empleados.IdEmpleado);
                        db.AddInParameter(dbcIngreso, "IdOrdenPedido", DbType.Int32, notaSalida.OrdenPedido.IdOrdenPedido);
                        db.AddInParameter(dbcIngreso, "descripcion", DbType.String, notaSalida.Descripcion);

                        db.ExecuteNonQuery(dbcIngreso, transaction);

                        #endregion
                        #region 2.2.- Registrar Detalles del Ingreso

                        DbCommand dbcDetalle = db.GetStoredProcCommand("InsertDetalleNotaSalida");

                        db.AddInParameter(dbcDetalle, "cantidad", DbType.Decimal);
                        db.AddInParameter(dbcDetalle, "IdNotaSalida", DbType.Int32);
                        db.AddInParameter(dbcDetalle, "IdBien", DbType.Int32);


                        DbCommand dbcProducto = db.GetStoredProcCommand("InsertDatosSalidaProducto");
                        db.AddInParameter(dbcProducto, "IdBien", DbType.Int32);
                        db.AddInParameter(dbcProducto, "stockActual", DbType.Decimal);

                        foreach (DetalleNotaSalida item in notaSalida.Detalle)
                        {
                            #region 2.2.1.- Verificar la existencia de Productos
                            // Si existe: Actualizar Cantidad
                            // No existe: Registrar Producto

                            db.SetParameterValue(dbcProducto, "IdBien", item.Bien.IdBien);
                            db.SetParameterValue(dbcProducto, "stockActual", -item.Cantidad);
                            db.ExecuteNonQuery(dbcProducto, transaction);


                            #endregion

                            #region 2.2.2.- Registrar Detalle

                            db.SetParameterValue(dbcDetalle, "cantidad", item.Cantidad);
                            db.SetParameterValue(dbcDetalle, "IdNotaSalida", notaSalida.IdNotaSalida);
                            db.SetParameterValue(dbcDetalle, "IdBien", item.Bien.IdBien);
                            db.ExecuteNonQuery(dbcDetalle, transaction);
                            #endregion
                        }

                        #endregion

                        #endregion
                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void Eliminar(int idNotaSalida)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        #region 1.- Retornar a su estado Inicial

                        #region 1.1.- Recoger Informacion Antigua

                        List<DetalleNotaSalida> detalle = DetalleNotaSalidaData.Instancia.ListarPorNotaSalida(idNotaSalida);

                        #endregion
                        #region 1.2.- Restar Cantidad de Bien

                        DbCommand dbcBienEdit = db.GetStoredProcCommand("InsertDatosProducto");
                        db.AddInParameter(dbcBienEdit, "IdBien", DbType.Int32);
                        db.AddInParameter(dbcBienEdit, "stockActual", DbType.Decimal);

                        foreach (DetalleNotaSalida item in detalle)
                        {
                            db.SetParameterValue(dbcBienEdit, "stockActual", item.Cantidad);
                            db.SetParameterValue(dbcBienEdit, "IdBien", item.Bien.IdBien);

                            db.ExecuteNonQuery(dbcBienEdit, transaction);
                        }

                        #endregion

                        #endregion

                        #region 2.- Eliminar NotaSalida

                        DbCommand dbcIngreso = db.GetStoredProcCommand("DeleteNotaSalida");

                        db.AddInParameter(dbcIngreso, "@IdNotaSalida", DbType.Int32, idNotaSalida);
                        db.ExecuteNonQuery(dbcIngreso);

                        #endregion

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public List<int> ListarPorGuia(List<int> arreglo)
        {
            List<int> notaSalidaID = new List<int>();
            DbCommand command = db.GetStoredProcCommand("GetAllIDNotaSalida");
            
            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    notaSalidaID.Add(dr.GetInt32(dr.GetOrdinal("IdNotaSalida")));
                };
            }
            List<int> arregloID = new List<int>();
            if (arreglo.Count > 0)
            {
                foreach (var item in arreglo)
                {

                    foreach (var variable in notaSalidaID)
                    {
                        if (variable != item)
                        {
                            arregloID.Add(variable);
                        }
                    }
                }
                return arregloID;
            }
            else
            {
                return notaSalidaID;
            }
        }
    }
}
